#include "MiniLib.h"
#include <asm-generic/socket.h>
#include <bits/getopt_ext.h>
#include <arpa/inet.h>
#include <bits/getopt_core.h>
#include <bits/getopt_ext.h>
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <iterator>
#include <string>
#include <cstdlib>
#include <pthread.h>
#include <signal.h>

#include <netinet/in.h>
// #include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
// #include <ctype.h>
// #include <strings.h>
#include <getopt.h>
// #include <pthread.h>
#include <thread>
// #include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <list>
#include <queue>
#include <iostream>

// #define _GNU_SOURCE

uint32_t startup(uint16_t &port) {
    // printf("%d\n",port);
    // uint32_t _socket;
    uint8_t ret;
    const uint32_t _socket = socket(PF_INET,
    SOCK_STREAM,
    IPPROTO_TCP);
    ERRO_REPROT(_socket, "Get socket")
    // MiniLog("成功获得套接字%d",_socket);
    // MiniLogf("成功获得套接字");

    char opt = 1;
    ret = setsockopt(_socket, 
    SOL_SOCKET, 
    SO_REUSEADDR, 
    &opt, 1);
    ERRO_REPROT(ret, "Set socket option")
    MiniLog("成功设置复用");
    
    struct sockaddr_in new_addr;
    memset(&new_addr, 0, sizeof(new_addr));
    new_addr.sin_family = PF_INET;
    new_addr.sin_port = htons(port);

    new_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    ret = bind(_socket, (struct sockaddr *)&new_addr, sizeof(new_addr));
    ERRO_REPROT(ret, "Can't bind the address")
    MiniLog("成功绑定套接字");
    // MiniLog("成功开启监听,套接字%d",_socket);
    // struct sockaddr_in nnew_addr;
    // int nsocket=_socket;
    if (port == 0) {
        // getsockname(_socket, NULL, NULL);
        // int __socket;
        uint8_t namelen = sizeof(new_addr);
        // ret = getsockname(_socket, 
        //                 // (struct sockaddr *)&new_addr,
        //                 (struct sockaddr*)&new_addr,
        //                 (socklen_t *)&namelen);
        // ERRO_REPROT(ret, "Can't set Port")
        // int chang=5;
        // MiniLog("成功开启监听,套接字%d LINE:%d",_socket,__LINE__);
        ret = getsockname(_socket, 
                        // (struct sockaddr *)&new_addr,
                        (struct sockaddr*)&new_addr,
                        (socklen_t *)&namelen);
        // MiniLog("成功开启监听,套接字%d LINE:%d",_socket,__LINE__);
        ERRO_REPROT(ret, "Can't read Port")
        port = htons(new_addr.sin_port);
        // MiniLog("成功开启监听,套接字%d",_socket);
        MiniLog("端口%d启动", port);
        // new_addr.sin_port=port;
        // // new_addr.sin_port=htons(8080);
        // port=2222;
    }

    ret = listen(_socket, 16);
    ERRO_REPROT(ret, "Can't create listen queue")
    // MiniLog("成功开启监听,套接字%d",_socket);

    return _socket;
}

void otheruser(uint32_t socket){
    std::list<std::string> httpstrlist;
    std::list<std::string> cmdlist;
    std::string wpath="NIL";
    // std::list<std::string> optlist;
    std::string cbuff;
    // char *buff=(char *)malloc(sizeof(char)*1024);
    std::string buff;
    // std::string fbuff;
    do {
        uint16_t numbers=HttpReadLine(buff, socket);
        // MiniLog("在[函数%s-第%d行]读取到\n%s\n",__func__,__LINE__,buff);
        // MiniLog("HTTP:\n%s\n,%d",buff.c_str(),buff.size());
        // std::cout<<buff;
        httpstrlist.push_back(buff);
    }while (buff=="\n");

    buff=httpstrlist.front();
    std::list<std::string>::iterator ibuff=httpstrlist.begin();
    // std::cout<<buff;
    std::ofstream qqf("qqfall");
    for(auto i:httpstrlist){
        qqf<<i;
    }
    qqf.close();
    for(auto i: buff){
        if(i==' '){
            if(!cbuff.empty()){
                cmdlist.push_back(cbuff);
                cbuff.clear();
            }
            continue;
        }else if (i=='\n') {
            cbuff='\n';
            cmdlist.push_back(cbuff);
        }
        cbuff+=i;
    }
    cbuff=cmdlist.front();
    std::list<std::string>::iterator cibuff=cmdlist.begin();
    if((*cibuff)!="GET" && (*cibuff)!="POST"){

        return;
    }

    
    if((*cibuff)=="GET"){
        // std::cout<<"againqq\n";
        cibuff=std::next(cibuff);
        if((*cibuff)=="/"){
            wpath="abc/index.html";
        }else {
            wpath="abc"+(*cibuff);
        }
        
        // std::ofstream of2("newsrc");
        // of2<<src;
        // std::cout<<"seeyouagain\n";
        std::cout<<wpath<<std::endl;
        send2client(socket,wpath);
        MiniLog("请求获取资源:%s",wpath.c_str());
    }


    
    
    // fsrc>>src;
    // std::cout<<src<<std::endl;

    // std::cout<<wpath<<std::endl;
    // cmdlist.push_back(cbuff);
    // cmmd=cmdlist.front();
    // std::cout<<cmmd;
    // for(auto i:cmdlist){
    //     std::cout<<i<<std::endl;
    // }

    // for (auto i:httpstrlist) {
    //     std::cout<<i;
    // }
    // std::cout<<buff<<std::endl;
    
    // for(auto i: buff){
    //     if (i==' '){
            
    //     }
    // }
    // free(buff);
}

int main(int argc, char **args) {
    int16_t opt;
    uint16_t port = 0;
    struct option LongOpt[]={
        {"port",1,NULL,'p'},
        {0,0,0,0}
    };
    while ((opt=getopt_long(argc, args, "p:", LongOpt, NULL))!=-1) {
        switch (opt) {
            case 'p':
            port=std::atoi(optarg);
            // std::cout<<optarg<<std::endl;
            // printf("get\n");
            break;
        }
    }
    
    signal(SIGINT, ctrlc);
    // printf("1\n");
    if(InitMiniLog()<0){
        return 1;
    }
    
    uint32_t new_socket;
    new_socket = startup(port);
    MiniLog("启动成功 正在监听%d端口", port);
    // fMiniLog(LogOut, "ok");
    // MiniLog("启动成功 正在监听%d端口", port);

    struct sockaddr_in client_addr;
    uint32_t client_addr_len = sizeof(client_addr);
    uint32_t client_sock;
    // MiniLog("hello %d ",1);
    while (1) {
        client_sock=accept(new_socket, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_len);
        ERRO_REPROT(client_sock, "Cant't get Client_socket");
        // printf("hhhhh\n");
        std::thread *t=new std::thread(otheruser,client_sock);
        
    }
    // accept(new_socket, (struct sockaddr *)&client_addr, &client_addr_len);
    
    close(new_socket);
    CloseMiniLog();
    return 0;
}